package jpf.nextsearch.util;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

/**
 * @author <a href="mailto:jacek.pruszkowski@gmail.com">Jacek Pruszkowski</a>
 * 
 */
public class Toolkit {
	/**
	 * 
	 * Funkcja do zamiany kazdego obiektu na Stringa. Glownie powinna byc
	 * uzywana do lowowania stanu obiektow (debug)
	 * 
	 * @param obj
	 *            obiekt ktoy ma zostac zamieniony na string
	 * @return String reprezentujacy dany obiekt
	 */
	public static String objectToString(Object obj) {
		if (obj == null) {
			return "null";
		}

		List<Object[]> parents = new ArrayList<Object[]>();
		parents.add(new Object[] { obj, "ROOT" });
		return objectToString(obj, 0, parents);
	}

	public static String prepareString(String str) {
		if (str == null) {
			return null;
		}
		str = str.trim();
		return str.length() == 0 ? null : str;
	}

	public static String getRequestURL(HttpServletRequest req) {
		String scheme = req.getScheme(); // http
		String serverName = req.getServerName(); // hostname.com
		int serverPort = req.getServerPort(); // 80
		String contextPath = req.getContextPath(); // mywebapp
		String servletPath = req.getServletPath(); // /servlet/MyServlet
		String pathInfo = req.getPathInfo(); // /a/b;c=123
		String queryString = req.getQueryString(); // d=789 // Reconstruct
		String url = scheme + "://" + serverName + ":"
				+ (serverPort == 80 ? "" : Integer.toString(serverPort))
				+ contextPath + servletPath;
		if (pathInfo != null) {
			url += pathInfo;
		}
		if (queryString != null) {
			url += "?" + queryString;
		}
		return url;
	}

	private static String objectToString(Object obj, int tabCount,
			List<Object[]> parents) {
		StringBuilder builder = new StringBuilder();
		Field[] fields = obj.getClass().getDeclaredFields();
		for (Field f : fields) {
			try {
				f.setAccessible(true);
				Class<?> type = f.getType();
				if (type.isPrimitive() || (type.isAssignableFrom(String.class))
						|| Number.class.isAssignableFrom(type)
						|| Character.class.isAssignableFrom(type)
						|| Boolean.class.isAssignableFrom(type)) {
					builder.append(tabs(tabCount) + f.getName() + " : "
							+ f.get(obj) + "\n");
				} else {
					if (f.get(obj) != null) {
						Object value = f.get(obj);
						boolean cycle = false;
						for (Object[] objs : parents) {
							StringBuilder parentBuilder = new StringBuilder();
							parentBuilder.append(" <-- " + ((String) objs[1])
									+ "\n");

							if (value == objs[0]) {
								builder.append(tabs(tabCount) + f.getName()
										+ " : " + parentBuilder.toString());
								cycle = true;
							}
						}
						if (!cycle) {
							builder.append(tabs(tabCount) + f.getName()
									+ " : \n");
							parents.add(new Object[] { value, f.getName() });
							builder.append(objectToString(f.get(obj),
									tabCount + 1, parents));
							parents.remove(parents.size() - 1);
						}
					} else {
						builder.append(tabs(tabCount) + f.getName()
								+ " : null\n");
					}
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return builder.toString();
	}

	public static String removeWhitespaces(String str) {
		if (str == null) {
			return null;
		}
		str = str.replaceAll("\\s+", " ").trim();
		return str.length() == 0 ? null : str;
	}

	private static String tabs(int count) {
		StringBuilder builder = new StringBuilder();
		for (int i = 0; i < count; i++) {
			builder.append("\t");
		}
		return builder.toString();
	}
}
